/**
*
* Orion 20m v2.0
* (c) 2011 AtomicDryad, orbiter-forums.com
* (c) 2004 Erik Anderson (Sputnik), erik_h_anderson@hotmail.com
*
*
* Licence LGPL -- http://www.gnu.org/licenses/lgpl.txt
*
* You may use this source code in your addon provided that if you
* publish your addon either privately or publicly the end user
* recieves a copy of the source code including any modifications
* you may have made. 
*
* 
*
* Requires CVEL library --                             
* please see ProjectGanymede on SourceForge for the latest source *
*/

#include "Orion20m.h"
#include "cvel.h"


void ORION::clbkFocusChanged(bool getfocus, OBJHANDLE hNewVessel, OBJHANDLE hOldVessel) {
	//dprint("focus(%d)",getfocus);
	if(cfg->cam>0) {
		if(getfocus) {
			if (oapiCameraInternal()) oapiCameraSetAperture(RAD * cameras[cfg->cam].apt / 2.0);
		} else {
			oapiCameraSetAperture(RAD * cameras[0].apt / 2.0);
		}
	}
}
/////	
///////////////////////
void ORION::clbkPreStep(double simt, double simdt, double mjd) {
	VECTOR3 cg;
	static double rcst=0.0;
	static double hudt=1.1;
	static double camt=1.1;
	double sstep=oapiGetSysStep();
	rcst += sstep;
	hudt += sstep;
	camt += sstep;
 
	if(cfg->cam > 0 && camt > 0.05) {
		camt=0.0;
		bool camin=oapiCameraInternal();
		if(camin && ! cfg->caminternal) {
			//syslog("chcam(in)");
			cfg->caminternal=true;
			oapiCameraSetAperture(RAD * cameras[cfg->cam].apt / 2.0);
		} else if (!camin && cfg->caminternal) {
			//syslog("chcam(out)");
			cfg->caminternal=false;
			oapiCameraSetAperture(RAD * cameras[0].apt / 2.0);
		}
		camt=0.0;
	}
	if (rcst>1.000) {		
		rcst=0.0;
		if(cfg->rcs_cog_comp==1) {
			GetSuperstructureCG(cg);
			double cgdist=dist(cg,shipcg);
			if(cgdist>0.0) {
				//dprint("(%s)newcg: %.8f, (%.4f,%.4f,%.4f) -> (%.4f,%.4f,%.4f)",GetName(),cgdist,shipcg,cg);
				//shipcg=cg;
				rcs_linshift(2);
			}
		}
		rcst=0.0;
	}
//	dprint("prestep: %f",oapiGetSysStep());
	if (hudt > 0.20) {
		hudt=0.0;
		UpdateHUDdata(cfg->hudmode);
		hudt=0.0;
	}
}

/////	prestep.(1)
///////////////////////
void ORION::getsuperstructuremass(VESSEL * ship) {
	//dprint("getsuperstructuremass: %s",ship->GetName());
	if (SSCOUNT>=MAXSUPERSTRUCTUREDEPTH) return;

	for (int x = 0; x < SSCOUNT; x++) {
		if(ship==superstructure[x].ref) {
			//dprint("  skipping dupe: %s",ship->GetName());
			return;
		}
	}
	
	superstructure[SSCOUNT].ref=ship;
	SSCOUNT++;

	ssmass=ssmass + ship->GetMass();

	DOCKHANDLE dockH;
	OBJHANDLE objH;
	int docks=0;
	docks=ship->DockCount();
	//dprint("  [%s] docks: %d",ship->GetName(),docks);
	for (int i = 0; i < docks; i++) {
		if(ship->DockingStatus(i)) {
			dockH=ship->GetDockHandle(i);
			objH=ship->GetDockStatus(dockH);
			VESSEL * veh = oapiGetVesselInterface(objH);
			//dprint("  [%s] dock %d/%d: %s",ship->GetName(),i,docks,veh->GetName());
			getsuperstructuremass(veh);
		}
	}
	return;
}

/////	
///////////////////////
void ORION::clbkPostStep(double simt, double simdt, double mjd) {
#ifdef CVEL
	if( CheckCentralMessage() ) SetMainStage();
#endif

	da = oapiGetSimStep() * SLAM_SPEED;
	SetThrusterGroupLevel(thg_orion, 0.0);

	SetAnimation (anim_slam, slam_proc);

	boom->Activate(0);
// Engine is on when the main throttle is up, or to continue the explosion cycle
	//if(cfg->nukeready) {
//	if(true) {
		if (((GetThrusterGroupLevel(thg_main)) > 0.25) || (slam_proc-da > 0.0))
			SlamCycle(da);
		if ( (cfg->nukearmed) && (slam_proc-da<0.0) )			// if we're NOT cycling, re-vector the thrust angle
			VectorThrust();
/*	} else {
		sc_proc += simdt * 0.1;
		if (sc_proc > 1) sc_proc -= 1;
		SetAnimation(anim_sc, sc_proc);

		if ( !cfg->nukearmed && slam_proc<1.0 ) {
			slam_proc=min(1.0,slam_proc + da/5 );
		} else if ( cfg->nukearmed && slam_proc>0.0 ) {
			slam_proc=max(0.0,slam_proc - da/5 );
			cfg->nukeready=(slam_proc==0.0?1:0);
		}
	}
*/
	//if (cfg->hudmode==HUD_CAMERA && 
	if( cfg->cam > 0 ) {
		int i=cfg->cam;
		double mod=(0.1*cameras[i].apt)/60;
		if(cfg->camyawmode==1.0) {
			cameras[i].yaw_proc += simdt * mod;
			if (cameras[i].yaw_proc > 1) cameras[i].yaw_proc -= 1;
			SetAnimation(cameras[i].anim_yaw, cameras[i].yaw_proc);
		} else if (cfg->camyawmode==-1.0) {
			cameras[i].yaw_proc -= simdt * mod;
			if (cameras[i].yaw_proc < 0) cameras[i].yaw_proc = 1;
			SetAnimation(cameras[i].anim_yaw, cameras[i].yaw_proc);
		}

		if(cfg->campitchmode==1.0) {
			cameras[i].pitch_proc += simdt * mod;
			if (cameras[i].pitch_proc > 1) cameras[i].pitch_proc -= 1;
			SetAnimation(cameras[i].anim_pitch, cameras[i].pitch_proc);
		} else if (cfg->campitchmode==-1.0) {
			cameras[i].pitch_proc -= simdt * mod;
			if (cameras[i].pitch_proc < 0) cameras[i].pitch_proc = 1;
			SetAnimation(cameras[i].anim_pitch, cameras[i].pitch_proc);
		}
		if(cfg->camanimlink) {
			if ( oapiCameraInternal() && 
				( cfg->camyawmode!=0.0 || 
					cfg->campitchmode!=0.0 ||
					cameras[cfg->cam].lastyaw != cameras[cfg->cam].yaw_proc ||
					cameras[cfg->cam].lastpitch != cameras[cfg->cam].pitch_proc
					) 
			) {
				cameras[cfg->cam].lastyaw = cameras[cfg->cam].yaw_proc;
				cameras[cfg->cam].lastpitch = cameras[cfg->cam].pitch_proc;
				VECTOR3 newdir;
				newdir=yawpitch2cart(
					cameras[cfg->cam].yaw_proc*PI*2,
					cameras[cfg->cam].pitch_proc*PI*2
				);
				cameras[cfg->cam].dir=newdir;
				SetCameraDefaultDirection(newdir);
				oapiCameraSetCockpitDir(0,0);

				SetCameraDefaultDirection(newdir);
				oapiCameraSetCockpitDir(0,0);
			}	
		}
	}
	ummu_clbkPostStep(simt,simdt,mjd);
}

/////	poststep.(1)
///////////////////////
void ORION::SetMainStage() {
	dprint("SetMainStage: start");
#ifdef CVEL
	ClearMeshesEx();
	PlaceComponents();
    Draw(_V(0,0,0));
#endif
	dprint("SetMainStage: done");
}

/////	poststep.(2)
///////////////////////
void ORION::SlamCycle(double da)
{
		if(!cfg->nukearmed) {
			if (cfg->nukewarned != 1) {
				cfg->nukewarned=1;
				syslog("ERROR: drive is OFFLINE. [ALT-A] to arm nukes.");
			}
			return;
		}

		PARTICLESTREAMSPEC exhaust_main = {
			0, 300, 0.4, 500, 0, 12, 50, 0.0, PARTICLESTREAMSPEC::EMISSIVE,
			PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
			PARTICLESTREAMSPEC::ATM_PLOG, 0, 0.1
		};
		if((havesound) && (firstnukestep) && (GetHandle() == oapiGetFocusObject())) {
			StopVesselWave3(MyID,5);
			PlayVesselWave3(MyID,5);								// Play the sound!  BIG boom!
			cloud = AddExhaustStream (th_orion[0],ExplosionPosition, &exhaust_main);
		}
		if (firstnukestep) { 
			
			
			firstnukestep = false;
			DestroyNeighbors(true);
		// todo: remove bomb from fuel at eject
			boomcount++;
#ifdef BOMBFUEL
			double vehfuelmass=GetFuelMass();
			SetFuelMass(vehfuelmass-500);
#endif
			
		}
		if (!MoveNegative) slam_proc = slam_proc + da*2;	// Plate moves faster compressing...
			else slam_proc = slam_proc - da;				// ...than expanding

		if (slam_proc+da*2 > 1.0) MoveNegative = true;		// Now we're expanding
		if (slam_proc-da < 0.0) 
		{
			slam_proc=0.0;				// FORCE the cycle ended
			MoveNegative = false;		// Now we'll compress, next bomb
		};
		SetThrusterGroupLevel(thg_orion, 1.0*cfg->nukeyield);				// Set Orion thrust "on"

// Vary the exhaust texture to make the flash
		DelExhaust(nuke);
		boom->Activate(0);
		nuke = AddExhaust (th_orion[0], 1.0, cfg->FlashSize*slam_proc*slam_proc*slam_proc*slam_proc, tex);
		boom->Activate(1);
		boom->SetIntensity((slam_proc*2)+0.5);

		if ((MoveNegative) || (slam_proc > da)) {
			DelExhaustStream (cloud);
		}// Stop making smoke puffs once we're done booming
/*
// Jiggle the ship a bit
		bombcounter+=1;
		if (bombcounter > 3) bombcounter=0;
		tempP = 500000*sin(fabs(jiggle_proc)*2*PI);
		tempY = 500000*sin(fabs(jiggle_proc)*2*PI);
		if (bombcounter == 1) tempP=tempP*-1;
		if (bombcounter == 2) tempY=tempY*-1;
		if (bombcounter == 3) {
			tempP=tempP*-1;
			tempY=tempY*-1;
		}
		AddForce(_V(tempY, tempP, 0), _V(0,0,20));
		AddForce(_V(-tempY, -tempP, 0), _V(0,0,-20));
		jiggle_proc+=(da*1.5);
		if (jiggle_proc > 1.0) jiggle_proc = -1.0;
*/
}

/////	poststep.(3)
///////////////////////
void ORION::VectorThrust()
{
// Vector the thrust (exploding bombs slightly off-center) 
// Only happens BETWEEN explosions, of course, never during them.
		
		if (oapiGetTimeAcceleration() > 10) return;
	
		tempP = GetManualControlLevel(THGROUP_ATT_PITCHDOWN, MANCTRL_ANYDEVICE, MANCTRL_ANYMODE) - 
			GetManualControlLevel(THGROUP_ATT_PITCHUP, MANCTRL_ANYDEVICE, MANCTRL_ANYMODE);

		tempY = GetManualControlLevel(THGROUP_ATT_YAWLEFT, MANCTRL_ANYDEVICE, MANCTRL_ANYMODE) - 
			GetManualControlLevel(THGROUP_ATT_YAWRIGHT, MANCTRL_ANYDEVICE, MANCTRL_ANYMODE);
	 
		GetAngularVel(AngularVel);
		tempP+=(10*AngularVel.x);			// Bias the thrust vector AGAINST the angular velocity a bit
		tempY+=(-10*AngularVel.y);			// This will damp angular velocity, preventing loss of control

		
		double fuelmass=GetFuelMass();

		double vlevel=((0.007*fuelmass)/cfg->FuelMass)+0.001; // crazy jiggling with low fuel

		SetThrusterDir(th_orion[0],_V(vlevel*tempY,vlevel*tempP,1));
		firstnukestep = true;
}
void ORION::chcamapt(int inout) {
	if(cfg->cam>0) {
       double oldapt=(oapiCameraAperture()/RAD) * 2;
	   double newapt=60.0;
	   if(inout>0){
			newapt=min(60.0,oldapt*2);
			//syslog("apt: %f -> %f",oldapt, newapt);
			//oapiCameraSetAperture(RAD * newapt / 2.0);
	   } else {
			newapt=max(0.2,oldapt/2);
			//syslog("apt: %f -> %f",oldapt, newapt);
			//oapiCameraSetAperture(RAD * newapt / 2.0);
	   }
	   if(newapt!=oldapt) {
		   oapiCameraSetAperture(RAD * newapt / 2.0);
			StopVesselWave3(MyID,6);
			PlayVesselWave3(MyID,6);
			cameras[cfg->cam].apt=newapt;
	   }
	}
}
/////	
///////////////////////
void ORION::chcamdir(int xyz,int leftright,double ang) {
	#define STEP (PI/36)
	if(cfg->cam>0) {
		VECTOR3 olddir,newdir;
		double mod;
mod=0.0;
		GetCameraDefaultDirection(olddir);
		newdir=olddir;

		if(leftright>0) {
			mod=STEP;
			switch(xyz) {
				case 0:
					newdir=rotatex(olddir,mod);
				break;
				case 1:
					newdir=rotatey(olddir,mod);
				break;
			}
		} else if (leftright<0) {
			mod=-STEP;
			switch(xyz) {
				case 0:
					newdir=rotatex(olddir,mod);
				break;
				case 1:
					newdir=rotatey(olddir,mod);
				break;
			}
		} else {
			switch(xyz) {
				case 0:
					newdir=rotatex(_V(0,0,1),ang);
				break;
				case 1:
					newdir=rotatey(_V(0,0,1),ang);
				break;
			}
			cameras[cfg->cam].dir=newdir;
			SetCameraDefaultDirection(newdir);
			oapiCameraSetCockpitDir(0,0);
			return;
		}
		cameras[cfg->cam].dir=newdir;
		SetCameraDefaultDirection(newdir);
		oapiCameraSetCockpitDir(0,0);
	}
}
/////	
///////////////////////
void ORION::chcam(int camnum) {
	VECTOR3 COFS,CDDIR;
	static int cmax=NUMCAMS-1;
	if(camnum>cmax) camnum=0;
	if(camnum<0) camnum=cmax;
	if(camnum==0) {
		if(cameras[0].apt>0.0) {
			oapiCameraSetAperture(RAD * cameras[0].apt / 2.0);
		}
		SetCameraOffset(cameras[0].pos);
		SetCameraDefaultDirection(cameras[0].dir);
		oapiCameraSetCockpitDir(0,0);
		VESSEL::SetMeshVisibilityMode(0,MESHVIS_EXTERNAL);
		VESSEL::SetMeshVisibilityMode(1,MESHVIS_EXTERNAL);
		VESSEL::SetMeshVisibilityMode(2,MESHVIS_EXTERNAL);
		cfg->cam=0;
	} else {
		if(cfg->cam==0) {
			cameras[0].apt=(oapiCameraAperture()/RAD) * 2;
		}
		oapiCameraSetAperture(RAD * cameras[camnum].apt / 2.0);
		SetCameraOffset(cameras[camnum].pos);
		SetCameraDefaultDirection(cameras[camnum].dir);
		oapiCameraSetCockpitDir(0,0);
		VESSEL::SetMeshVisibilityMode(0,MESHVIS_ALWAYS);
		VESSEL::SetMeshVisibilityMode(1,MESHVIS_ALWAYS);
		VESSEL::SetMeshVisibilityMode(2,MESHVIS_ALWAYS);
		cfg->cam=camnum;
	}
	GetCameraOffset(COFS);
	GetCameraDefaultDirection(CDDIR);
#ifdef TESTING
	syslog("camera %i selected. pos: %.4f,%.4f,%.4f, dir: %.4f,%.4f,%.4f, ap: %f",camnum,COFS,CDDIR,oapiCameraAperture());
#endif
	return;
}
/////	
///////////////////////
void ORION::DestroyNeighbors(bool nukestep) {
	if(nukestep!=true) return; // wtf bleh this procs twice...simstep is wonky...fixlater.
	if(cfg->Destructive==0) return;

	sprintf(oapiDebugString(), "");
	Local2Global (ExplosionPosition, gorion);  // global position of the nuke explosion
	j = oapiGetVesselCount();
	for (i = 0; i < j; i++) {
		j = oapiGetVesselCount();			// Last-ditch check to prevent using oapiGetVesselByIndex
		if (i >= j) return;					// if some other vessel has changed the index on us
		hV = oapiGetVesselByIndex (i);
		if (hV == GetHandle()) continue; // we don't want to destroy ourselves ...
		oapiGetGlobalPos (hV, &gpos);
		distance = dist(gpos,gorion); // 10,10,10 11,11,11 = 1.73205
		if (distance < cfg->DestructRange) { // in range
			Global2Local (gpos,lpos); // 1,1,1 ///// 1,1,-76
			olpos=lpos;
			lpos.x=lpos.x/distance; // .57735
			lpos.y=lpos.y/distance; // .57735
			lpos.z=lpos.z+-(ExplosionPosition.z/2); // -76+(-75/2) = -113.5
			lpos.z=lpos.z/distance; // -113.5/1.73205 = -65.52
			if ((lpos.z < 0.0) || (lpos.x*lpos.x+lpos.y*lpos.y > lpos.z*lpos.z))  // Small angle-off from forward axis
				// .333333+.333333 = .66666 > -131.04 //////
													// We won't hit anything protected by our pusher plate
			{
				if (hV == oapiGetFocusObject())			// If we're trying to destroy the focus object
					oapiSetFocusObject(GetHandle());	// Switch to the destroying object
					
				VESSEL *remotevessel = oapiGetVesselInterface(hV);					
				VESSELSTATUS hv;
				oapiGetObjectName(hV,destructname,256);	
				dprint("Destroy: %s: dist: %.2f, gpos(%.2f,%.2f,%.2f) lpos(%.2f,%.2f,%.2f -> %.2f,%.2f,%.2f)",destructname,distance,gpos,olpos,lpos);
/*
					oapiGetGlobalPos (GetHandle(), &gpos);
					remotevessel->Global2Local (gpos,lpos);		// Check to see if it's protected
					lpos.x=lpos.x/distance;						// by its pusher plate
					lpos.y=lpos.y/distance;
					lpos.z=lpos.z/distance;
*/
				if (!_strnicmp (remotevessel->GetClassName(), "Orion", 5) != 0)		// If the target is an Orion also,
				{				
					oapiGetGlobalPos (GetHandle(), &gpos);
					remotevessel->Global2Local (gpos,lpos);		// Check to see if it's protected
					lpos.x=lpos.x/distance;						// by its pusher plate
					lpos.y=lpos.y/distance;
					lpos.z=lpos.z/distance;
					if ((lpos.z < 0.0) && (lpos.x*lpos.x+lpos.y*lpos.y < lpos.z*lpos.z)) { // Small angle-off from forward axis	
						sprintf(oapiDebugString(),"%s protected by pusher plate",destructname);
						continue;
					}
				}
	
				
				if ((remotevessel->GetFuelMass() > 0.0) && (distance > (cfg->DestructRange / 2))) {					
					remotevessel->SetFuelMass(0.0);		// Now it's a fuel-less, non-maneuvering wreck
					sprintf(oapiDebugString(),"Damaged %s due to nuclear blast",destructname);
					syslog("Damaged %s due to nuclear blast",destructname);
				}				
				else {
					remotevessel->Undock(ALLDOCKS);		// Undock everything.  Doesn't work right otherwise
					remotevessel->SetFuelMass(0.0);		// Damage it too.  Wouldn't want to forget that
					remotevessel->GetStatus(hv);
//					oapiDeleteVessel(hV);				// This works, but screws up the index
					OBJHANDLE oh=remotevessel->GetGravityRef();
					int wtf=oapiGetObjectType(oh);
					if(wtf!=4) { // != 4 == not a planet == crash
						remotevessel->AddForce(operator * (lpos,500000000),lpos); //todo: this could be better with spin and such
						//syslog("DESTROYED %s due to nuclear blast (%i) %.0f,%.0f,%.0f /  %.0f,%.0f,%.0f",destructname,wtf,lpos,operator * (lpos,500000000));
					} else {
						hv.status=1;						// Instead, we'll set status to "landed"
						remotevessel->DefSetState(&hv);		// That'll fix 'em!
					}
					sprintf(oapiDebugString(),"Destroyed %s due to nuclear blast",destructname);
					syslog("DESTROYED %s due to nuclear blast.",destructname);
				}

			}
		}
	}
}
/////	
///////////////////////
void ORION::clbkSaveState( FILEHANDLE scn ) {
	dprint("clbkSaveState: start")
	SaveDefaultState (scn);

	/* CVE-lite function ! */
	/* IMPORTANT */
	/* Call this after the normal SaveDefautState() to record attached payloads
	/* it the scenario file */

	/* save payload lines */
#ifdef CVEL
	SaveDefaultStateEx(scn);
#endif
	///todo
	Crew.SaveAllMembersInOrbiterScenarios(scn);
	oapiWriteScenario_int (scn, "HUDMODE",cfg->hudmode);
	oapiWriteScenario_int (scn, "EVASEL",SelectedUmmuMember);
	oapiWriteScenario_int (scn, "DOCKSEL",SelectedUmmuDock);
	oapiWriteScenario_int (scn, "DOCKLIGHT",evalight->IsActive());
	oapiWriteScenario_int (scn, "COG_COMP",cfg->rcs_cog_comp);
	oapiWriteScenario_float(scn,"NUKEYIELD",cfg->nukeyield);
	oapiWriteScenario_int(scn,"NUKEARMED",cfg->nukearmed);
	char tmpstr[6];
	sprintf(tmpstr,"%1i %1i %1i",cfg->nukesafety1,cfg->nukesafety2,cfg->nukesafety3);
	tmpstr[6]=0;
	oapiWriteScenario_string(scn,"NUKESAFE",tmpstr);
	oapiWriteScenario_int (scn, "CAMERA",cfg->cam);
	char camstr[32];
	for(int i=1;i<NUMCAMS;i++) {
		sprintf(camstr,"%i %.4f %.4f %.4f",i,cameras[i].yaw_proc,cameras[i].pitch_proc,cameras[i].apt);
		oapiWriteScenario_string(scn,"CAMSET",camstr);
	}
	//oapiWriteScenario_int(scn,"NUKELOCK",cfg->nukesafety1+(cfg->nukesafety2*10)+(cfg->nukesafety2*100));
	dprint("clbkSaveState: done")
}
/////	
///////////////////////
void ORION::chhud(int num) {
	char *menuTitle[5] = {"Hud off","Main", "RCS", "MMU/Docking","Test"};//,"Lighting"}; // FIXME: dynamic
	if(num>HUDMENUCOUNT) return;
	cfg->hudmode=num;
	int nextmode=num+1;
	if(nextmode>=HUDMENUCOUNT) nextmode=0;
	sprintf(hudtitle,"%s menu -- [U] %s",menuTitle[num],menuTitle[nextmode]);
}
/////	
///////////////////////
void ORION::chyield(int updown) {
	double newyield;
	if(!updown) {
		newyield=cfg->nukeyield/2;
		if(newyield<0.25) newyield=0.10;
	} else {
		newyield=cfg->nukeyield*2;
		if(newyield<0.25) newyield=0.25;
		else if(newyield>1.00) newyield=1.00;
	}
	cfg->nukeyield=newyield;
	syslog("Bomb yield set to %.0f%%",newyield*100);
}
/////	
///////////////////////
int ORION::armnuke(int onoff) {
	if(onoff==cfg->nukearmed) {
		syslog("ERROR: Nuclear pulse engine is already %s.",(onoff?"online":"offline"));
	} else if(onoff) {
		if(cfg->nukesafety1+cfg->nukesafety2+cfg->nukesafety3 > 0) {
			syslog("ERROR: Nuclear safeties set. To arm, enter: %s%s%s.",
				(cfg->nukesafety1?" [ALT-1]":""),
				(cfg->nukesafety2?" [ALT-2]":""),
				(cfg->nukesafety3?" [ALT-3]":"")
			);
		} else {
			syslog("WARNING: Nuclear pulse engine now ONLINE.");// Yield: %.0f%",cfg->nukeyield*100);
			cfg->nukearmed=1;
		}
	} else {
		syslog("Nuclear pulse engine now OFFLINE.");
		cfg->nukearmed=0;
		cfg->nukeready=0;
		cfg->nukewarned=0;
	}
	return cfg->nukearmed;
}






/*
int ORION::clbkConsumeBufferedKey(DWORD key, bool down, char *keystate)
{


		if (!down) return 0; // only process keydown events

		if (KEYDOWN (keystate, OAPI_KEY_J) && !KEYMOD_CONTROL(keystate) && !KEYMOD_SHIFT(keystate) ) 
		{ // "Jettison Stage"
			if (oapiAcceptDelayedKey (OAPI_KEY_J, 1.0))
			{
				VESSEL *depV;
				VECTOR3 glopos, locpos;
				VESSELSTATUS vs;
				double payrot;

				depV = DeployPayload(_V(0,0,0));
				if (depV || NULL) {
					depV->GetGlobalPos(glopos);
					Global2Local (glopos, locpos);
					depV->GetStatus(vs);
					if ((strnicmp (depV->GetClassName(), "zrot", 4) == 0)
						|| (strnicmp (depV->GetClassName(), "Orion/zrot", 10) == 0)) {	// If the target class starts with "zrot" in it, 
																				//	then we can do this routine
						payrot = atan(locpos.x/locpos.y);
						if ((locpos.y < 0)) payrot += PI;
						if ((strnicmp (depV->GetClassName(), "zrot180", 7) != 0)
							&& (strnicmp (depV->GetClassName(), "Orion/zrot180", 13) != 0)) // If it starts with zrot180, spin it another 180
							payrot += PI;
						vs.arot.z += payrot;
						depV->DefSetState(&vs);
					}
				}

				ClearMeshesEx();
				PlaceComponents();
				Draw(_V(0,0,0));
				SetEmptyMass ( cfg->EmptyMass + CalculateMass () );
				SetAttControlsOrion();
			}
			UnDockArm = false;
			return 1;
		}
		if (KEYDOWN (keystate, OAPI_KEY_C) && KEYMOD_CONTROL(keystate) && !KEYMOD_SHIFT(keystate) ) 
		{ // "Jettison Stage"
//			if (oapiAcceptDelayedKey (OAPI_KEY_C, 1.0))
//				dock1=CreateDock( _V(0,0.0,2.0), _V(0,0,1), _V(0,1,0));
			
			UnDockArm = false;
			return 1;
		}
		

		if (KEYDOWN (keystate, OAPI_KEY_E) && !KEYMOD_CONTROL(keystate) && !KEYMOD_SHIFT(keystate) ) 
		{ 
			if (oapiAcceptDelayedKey (OAPI_KEY_E, 1.0))
		{
			

				VESSELSTATUS vs;
				OBJHANDLE hvessel;
				GetStatus (vs);
				vs.eng_main = vs.eng_hovr = 0.0;
				vs.fuel=1.0;
				vs.status=0;
				VECTOR3 ofs = _V(1.8,1.8,24.25);
				Local2Rel (ofs, vs.rpos);
				char name[256], name2[256];
			//	strcpy (name, GetName()); strcat (name, "-PLT");


				UINT i;
				for (i=1;i<8;i++) {
						strcpy (name2, GetName()); 
						sprintf(name, "-EV%d", i);
						strcat (name2, name);
						hvessel=oapiGetVesselByName(name2);
						if (hvessel == 0) break;
				}		
				if ( i < 7) 
				{
					VESSEL::Create (name2, "gemini_leva", vs);
					hvessel=oapiGetVesselByName(name2);
					oapiSetFocusObject(hvessel);
				}

	
			}
			
			UnDockArm = false;
			return 1;
		}
*/
/*		if (KEYDOWN (keystate, OAPI_KEY_D) && KEYMOD_CONTROL(keystate) && !KEYMOD_SHIFT(keystate) ) 
		{ // "Undock"
			if (!UnDockArm)
				UnDockArm = true;
			else {
				Undock(ALLDOCKS);
				UnDockArm = false;
			}
			return 1;
		}
		if (KEYDOWN (keystate, OAPI_KEY_0) && !KEYMOD_CONTROL(keystate) && !KEYMOD_SHIFT(keystate) && UnDockArm ) 
		{ // "Undock the numbered port"
			Undock(0);
			UnDockArm = false;
			return 1;
		}
	return 0;
}
*/


/*
void ORION::clbkDrawHUD(int mode, const HUDPAINTSPEC *hps, HDC hDC) {
	VESSEL2::clbkDrawHUD (mode, hps, hDC);
	side_offset + 10, _from_top
*/
///////////////////////
#define shiftlingr(g,str){int thcount=GetGroupThrusterCount(g);\
	for (int i = 0; i < thcount; i++) {\
		th = GetGroupThruster(g, i);\
		GetThrusterRef(th, thref);\
		thmax=GetThrusterMax0(th);\
		if(thref.z==RCS_LIN_F_ZPOS) {\
			SetThrusterMax0(th,cfg->RCSThrust*(fzratio/1));\
		} else if (thref.z==RCS_LIN_B_ZPOS) {\
			SetThrusterMax0(th,cfg->RCSThrust*(bzratio/1));\
		}\
		thmax=GetThrusterMax0(th);\
	}\
}
/////	
///////////////////////
void ORION::rcs_linshift(int onoff) {
	VECTOR3 thref;
	THRUSTER_HANDLE th;
	double thmax;
	GetSuperstructureCG(shipcg);
	double bzratio=RCS_LIN_B_RATIO;
	double fzratio=RCS_LIN_F_RATIO;

	/*	HURR-DURR: calc via sqrt ( ((cg.x+ref.x)^2)+((cg.z+ref.z)^2) ) etc */
	if(onoff>0) {
		double fzdiff=RCS_LIN_F_ZPOS-(shipcg.z);
		double bzdiff=(RCS_LIN_B_ZPOS-(RCS_LIN_B_ZPOS*2))+(shipcg.z);
		if(fzdiff <= 0 || bzdiff <= 0) {
			if (onoff==1) syslog("shift-z: cg: %.8f, out of bounds.",shipcg.z);
		} else {
			bzratio=fzdiff/bzdiff;									// 1.14
			if(bzratio>RCS_LIN_B_RATIO) {							// 1.14>4
				fzratio=RCS_LIN_B_RATIO/bzratio;					// 
				bzratio=RCS_LIN_B_RATIO;							//
			}
		}
		if (onoff==1) syslog("shift-z: zratio f/b: %.8f/%.8f",fzratio,bzratio);
	} else {
		syslog("shift-z: off. zratio f/b: %.8f/%.8f",fzratio,bzratio);		
	}
	shiftlingr(THGROUP_ATT_UP,"U");
	shiftlingr(THGROUP_ATT_DOWN,"D");
	shiftlingr(THGROUP_ATT_LEFT,"L");
	shiftlingr(THGROUP_ATT_RIGHT,"R");
	return;
}
/////	
///////////////////////
void ORION::clbkVisualCreated( VESSEL *vessel, VISHANDLE vis, int refcount ) {
	dprint("clbkVisualCreated: start");
#ifdef CVEL
	ClearMeshesEx();
	PlaceComponents();
    Draw(_V(0,0,0));
#endif
	dprint("clbkVisualCreated: done");
}
